﻿using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Linq;
using System.Windows;
using System.IO;
using Microsoft.Win32;
using ParsecClient.Classes;
using System.Diagnostics;
using ParsecParser;
using ParsecParser.Data;
using ParsecParser.Helpers;
using ParsecParser.Communication;
using ParsecParser.Display;
using ParsecClient.ParsecRaidWebService;
using System.ServiceProcess;

namespace ParsecClient
{
    /// <summary>
    /// Interaction logic for App.xaml
    /// </summary>
    public partial class App : Application
    {
        public const string AppVersion = "1.0.0.53";
        public bool UseRaidServiceCompression = false;
        public bool IsPingVisible = false;
        public bool IsArchiveEnabled = false;
        public bool AreTimersEnabled = false;
        public bool IsStreamMode = false;
        public bool IsSoftwareRenderingMode = false;
        public List<CharacterSettings> AllCharacterSettings = new List<CharacterSettings>();
        public List<string> RecentFiles = new List<string>();
        public List<RaidGroup> RaidGroups = new List<RaidGroup>();
        private object TimerDefinitionLock = new object();
        private List<TimerDefinition> TimerDefinitions = new List<TimerDefinition>();
        public Window PopUpHost;
        public StatsOverview StatPopOut;
        public StatStopWatch StatStopWatchPopOut;
        public RaidDps RaidDpsPopOut;
        public RaidHps RaidHpsPopOut;
        public RaidTps RaidTpsPopOut;
        public DpsMeter DpsMeterPopOut;
        public TimerPop TimerPopOut;
        public MessageWindow MyMessageWindow;
        public int VolumeSetting = 100;
        private SNTPClient SNTPTimeServer;
        public string DefaultTimeServer;
        private bool TimeServerOk = true;
        public bool TimeSyncEnabled = true;
        public bool TimeServerDefault = true;
        public string TimeServerHostNameSetting = null;
        public int TimeServerPortSetting = 0;
        public DateTime LastTimeServerUpdate;
        #region Constants
        private const string DefaultLogPath = "Star Wars - The Old Republic\\CombatLogs\\";
        public const string ParsecSignUpUrl = "http://www.ParsecParser.com/SignUp.aspx";
        public const string ParsecShareUrl = "http://www.ParsecParser.com/ViewFight.aspx?fid={0}";
        public const string EncryptionKey = "NotGivingYouThat";
        public const int TimeSyncRefreshInterval = 45;
        #endregion

        public List<TimerDefinition> GetTimerDefinitions()
        {
            lock (TimerDefinitionLock)
            {
                return TimerDefinitions.ToList();
            }
        }
        public TimerDefinition GetTimerDefinition(string description)
        {
            lock (TimerDefinitionLock)
            {
                return TimerDefinitions.FirstOrDefault(x => string.Compare(x.Description, description) == 0);
            }
        }
        public void SetTimerDefinitions(List<TimerDefinition> t)
        {
            if (t != null)
            {
                lock (TimerDefinitionLock)
                {
                    TimerDefinitions = t;
                }
            }
        }
        public void AddTimerDefinition(TimerDefinition t)
        {
            if (t != null)
            {
                lock (TimerDefinitionLock)
                {
                    TimerDefinitions.Add(t);
                }
            }
        }
        public void RemoveTimerDefinition(string description)
        {
            lock (TimerDefinitionLock)
            {
                TimerDefinitions.RemoveAll(x => string.Compare(x.Description, description) == 0);
            }
        }
        private void Application_Startup(object sender, StartupEventArgs e)
        {
            try
            {
                Logger.WriteInfo("Parsec Startup " + AppVersion);
                FrameworkElement.LanguageProperty.OverrideMetadata(typeof(FrameworkElement), new FrameworkPropertyMetadata(System.Windows.Markup.XmlLanguage.GetLanguage(System.Globalization.CultureInfo.CurrentCulture.IetfLanguageTag)));
                UseRaidServiceCompression = Convert.ToBoolean(ConfigurationManager.AppSettings["UseRaidServiceCompression"] ?? "true");
                IsPingVisible = Convert.ToBoolean(ConfigurationManager.AppSettings["ShowPing"] ?? "true");
                IsArchiveEnabled = Convert.ToBoolean(ConfigurationManager.AppSettings["EnableDataArchive"] ?? "true");
                AreTimersEnabled = Convert.ToBoolean(ConfigurationManager.AppSettings["EnableTimers"] ?? "true");
                DefaultTimeServer = ConfigurationManager.AppSettings["TimeServer"] ?? "";
                AllCharacterSettings = CharacterSettingsCollection.RetrieveCharacterSettings();
                try
                {
                    LoadSystemSettings();
                }
                catch (Exception ex)
                {
                    //write to log
                    ((App)Application.Current).HandleError(null, "Settings Error, Attempting Reset!", ex, null, true);
                    ResetSettings(false, false);
                }
                UpdateTimeSync(true);
                if (IsSoftwareRenderingMode)
                    System.Windows.Media.RenderOptions.ProcessRenderMode = System.Windows.Interop.RenderMode.SoftwareOnly;
                MainWindow = new ParsecWindow();
                StatPopOut = new StatsOverview();
                RaidDpsPopOut = new RaidDps();
                RaidHpsPopOut = new RaidHps();
                RaidTpsPopOut = new RaidTps();
                TimerPopOut = new TimerPop();
                DpsMeterPopOut = new DpsMeter();
                StatStopWatchPopOut = new StatStopWatch();
                PopUpHost = new Window();
                PopUpHost.Top = SystemParameters.VirtualScreenTop - 100;
                PopUpHost.Left = SystemParameters.VirtualScreenLeft - 100;
                PopUpHost.Width = 1;
                PopUpHost.Height = 1;
                PopUpHost.WindowStyle = WindowStyle.ToolWindow;
                PopUpHost.Show();
                PopUpHost.Hide();

                try
                {
                    LoadWindowSettings();
                    ((ParsecWindow)MainWindow).BindRaidGroups();
                    ((ParsecWindow)MainWindow).BindRecentFiles();
                    ((ParsecWindow)MainWindow).BindTimerDefinitions();
                }
                catch (Exception ex)
                {
                    ((App)Application.Current).HandleError(null, "Settings Error, Attempting Reset!", ex, null, true);
                }
                if (IsStreamMode)
                {
                    SetStreamMode(MainWindow, true, ParsecClientHelpers.WhiteBackground);
                    SetStreamMode(StatPopOut, true, ParsecClientHelpers.BlackBackground);
                    SetStreamMode(StatStopWatchPopOut, true, ParsecClientHelpers.BlackBackground);
                    SetStreamMode(RaidDpsPopOut, true, ParsecClientHelpers.BlackBackground);
                    SetStreamMode(RaidHpsPopOut, true, ParsecClientHelpers.BlackBackground);
                    SetStreamMode(RaidTpsPopOut, true, ParsecClientHelpers.BlackBackground);
                    SetStreamMode(TimerPopOut, true, ParsecClientHelpers.BlackBackground);
                    SetStreamMode(DpsMeterPopOut, true, ParsecClientHelpers.BlackBackground);
                }

                //check for commandline args
                //string openFilePath = null;
                //string[] args = Environment.GetCommandLineArgs();
                //for (int index = 1; index < args.Length; index++)
                //{
                //    string argString = args[index];
                //    if (!string.IsNullOrEmpty(argString.Trim()))
                //    {
                //        if (string.Compare(argString, "/resetsettings", true) == 1)
                //        {
                //            ResetSettings(false, false);
                //        }
                //        else if (argString.IndexOfAny(System.IO.Path.GetInvalidPathChars()) == -1)
                //        {
                //            try
                //            {
                //                if (File.Exists(argString) && string.Compare(System.IO.Path.GetExtension(argString), ".txt", true) == 0)
                //                {
                //                    openFilePath = argString;
                //                    break;
                //                }
                //            }
                //            catch
                //            {
                //                //do nothing
                //            }
                //        }
                //    }
                //}
                MainWindow.ShowActivated = false;
                MainWindow.Show();
                //if (!string.IsNullOrEmpty(openFilePath))
                //    ((ParsecWindow)MainWindow).OpenLogFile(openFilePath);

                if (ParsecClient.Properties.Settings.Default.LastRunVersion != AppVersion)
                {
                    ((ParsecWindow)MainWindow).ShowNotes();
                    ParsecClient.Properties.Settings.Default.LastRunVersion = AppVersion;
                    ParsecClient.Properties.Settings.Default.Save();
                }

                if (TimeSyncEnabled && (SNTPTimeServer == null || !SNTPTimeServer.IsResponseValid()))
                {
                    try
                    {
                        //attempt to correct time service problem
                        using (var controller = new System.ServiceProcess.ServiceController("w32time"))
                        {
                            if (controller != null && controller.Status != ServiceControllerStatus.Stopped)
                            {
                                //controller.Stop();
                                if (HandleAskMessage("Parsec cannot synchronize its time because the Windows has locked the Time Server network port. Would you like Parsec to open this port (recommended)? \r\n\r\nWindows will reclaim the port the next time it is scheduled to sync your clock.", null))
                                {
                                    var p = new System.Diagnostics.ProcessStartInfo();
                                    p.UseShellExecute = true;
                                    p.CreateNoWindow = false;
                                    p.WorkingDirectory = Environment.GetFolderPath(Environment.SpecialFolder.System);
                                    p.FileName = "cmd.exe";
                                    p.Arguments = @"/c net stop w32time";
                                    p.Verb = "runas";
                                    System.Diagnostics.Process.Start(p);
                                    try
                                    {
                                        controller.WaitForStatus(ServiceControllerStatus.Stopped, new System.TimeSpan(0, 0, 0, 10, 0));
                                    }
                                    catch (System.ServiceProcess.TimeoutException ex)
                                    {
                                        ((App)Application.Current).HandleError(string.Format("Parsec was unable to verify that the service was stopped"), "Service Stop Timeout Exceeded", ex, null, false);
                                    }
                                    RestartTimeSync();
                                    UpdateTimeSync(true);
                                }
                            }
                            if (controller != null)
                                controller.Close();
                        }
                    }
                    catch (Exception ex)
                    {
                        Logger.WriteError("Unknown Error attempting to fix Time Service Problem", ex);
                    }
                }
                if (TimeSyncEnabled && (SNTPTimeServer == null || !SNTPTimeServer.IsResponseValid()))
                {
                    string timeServerHostName = TimeServerDefault ? DefaultTimeServer : TimeServerHostNameSetting;
                    ((App)Application.Current).HandleError(string.Format("Parsec was unable to contact the time server ({0}).\r\n Check your Time Sync settings in File > Settings > Time Sync.\r\n Parsec will continue to function but your timers may be out of sync.", timeServerHostName ?? "Not Set"), null, null, null, false);
                }
            }
            catch (Exception ex)
            {
                Logger.WriteError("Critical Error on Startup", ex);
                MessageBox.Show("Error Staring Parsec: " + ex.Message);
                this.Shutdown();
            }
        }
        public DateTime GetCurrentServerTime()
        {
            if (SNTPTimeServer == null)
                return DateTime.Now;
            else if (!SNTPTimeServer.IsResponseValid())
                return DateTime.Now;
            else
                return DateTime.Now.AddMilliseconds(SNTPTimeServer.LocalClockOffset);
        }
        public void RestartTimeSync()
        {
            SNTPTimeServer = null;
            LastTimeServerUpdate = new DateTime();
            TimeServerOk = true;
        }
        public bool IsTimeServerRunning()
        {
            return TimeServerOk;
        }
        public string GetTimeServerStatus()
        {
            string status = "";
            string offset ="0";
            string timeServerHostName = TimeServerDefault ? DefaultTimeServer : TimeServerHostNameSetting;
            int timeServerPort = TimeServerDefault ? 123 : TimeServerPortSetting;
            if (TimeSyncEnabled)
            {
                if (SNTPTimeServer != null)
                {
                    status = SNTPTimeServer.IsResponseValid() ? "OK" : "OFFLINE";
                    offset = SNTPTimeServer.IsResponseValid() ? SNTPTimeServer.LocalClockOffset.ToString() : "0";
                }
                else
                {
                    status = "UNINITIALIZED";
                }
            }
            else
            {
                status = "DISABLED";
            }
            return string.Format("Host: {2}:{3} Status: {0} Offset: {1} Last Update: {4}", status, offset, timeServerHostName, timeServerPort.ToString(), LastTimeServerUpdate.ToLocalTime().ToString("h:mm:ss.fff"));
        }
        public void HandleError(string errorMessage, string logMessage, Exception ex, Window owner, bool showException)
        {
            if (!this.Dispatcher.CheckAccess())
            {
                this.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Normal, (Action)delegate { HandleError(errorMessage, logMessage, ex, owner, showException); });
                return;
            }
            else
            {
                try
                {
                    if (!string.IsNullOrEmpty(errorMessage))
                    {
                        if (ex != null && showException)
                            errorMessage += Environment.NewLine + ex.Message;
                        if (MyMessageWindow != null)
                            MyMessageWindow.Close();
                        MyMessageWindow = new MessageWindow(errorMessage, true, false, false, false);
                        MyMessageWindow.ShowActivated = false;
                        if (owner == null)
                            owner = this.MainWindow;

                        MyMessageWindow.Owner = owner;
                        //if (modalize)
                        //    MyMessageWindow.ShowDialog();
                        //else
                        //{
                        MyMessageWindow.Owner.IsEnabled = false;
                        MyMessageWindow.Show();
                        //}
                    }
                    if (!string.IsNullOrEmpty(logMessage))
                    {
                        if (ex == null)
                            Logger.WriteError(logMessage);
                        else
                            Logger.WriteError(logMessage, ex);
                    }
                }
                catch (Exception ex2)
                {
                    Logger.WriteError("Critical Error on Exception", ex2);
                    MessageBox.Show(logMessage);
                }
            }
        }
        public void HandleMessage(string msg, Window owner)
        {
            if (!this.Dispatcher.CheckAccess())
            {
                this.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Normal, (Action)delegate { HandleMessage(msg, owner); });
                return;
            }
            else
            {
                if (!string.IsNullOrEmpty(msg))
                {
                    if (MyMessageWindow != null)
                        MyMessageWindow.Close();
                    MyMessageWindow = new MessageWindow(msg, false, false, true, true);
                    if (owner != null)
                        MyMessageWindow.Owner = owner;
                    else
                        MyMessageWindow.Owner = this.MainWindow;
                    MyMessageWindow.ShowDialog();
                }
            }
        }
        public bool HandleAskMessage(string msg, Window owner)
        {              
            if (!string.IsNullOrEmpty(msg))
            {
                MessageWindow m = new MessageWindow(msg, false, true, true, true);
                if (owner != null)
                    m.Owner = owner;
                else
                    m.Owner = this.MainWindow;
                return m.ShowDialog() ?? false;
            }
            return false;
        }
        public static void SetStreamMode(Window w, bool isStream, System.Windows.Media.SolidColorBrush background)
        {
            if (w != null)
            {
                if (isStream)
                {
                    w.AllowsTransparency = false;
                    //w.WindowStyle = System.Windows.WindowStyle.SingleBorderWindow;
                    w.Background = background;
                }
                else
                {
                    w.AllowsTransparency = true;
                    //w.WindowStyle = System.Windows.WindowStyle.None;
                    w.Background = background;
                }
            }
        }
        public void ResetSettings(bool resetGroups, bool resetTimers)
        {
            if (!resetGroups)
            {
                var rg = RaidGroups;
                ParsecClient.Properties.Settings.Default.Reset();
                LoadSystemSettings();
                LoadWindowSettings();
                RaidGroups = rg;
                SaveSettings();
            }
            else
            {
                ParsecClient.Properties.Settings.Default.Reset();
                LoadSystemSettings();
                LoadWindowSettings();
            }
            if (resetTimers)
            {
                TimerDefinitionCollection.DeleteAllTimerDefinition();
                TimerDefinitions = TimerDefinition.GetDefaults();
            }
            CharacterSettingsCollection.DeleteAllCharacterSettings();
            AllCharacterSettings = CharacterSettingsCollection.RetrieveCharacterSettings();
            ((ParsecWindow)MainWindow).BindRaidGroups();
            ((ParsecWindow)MainWindow).BindRecentFiles();
        }
        public void SaveSettings()
        {
            if (!this.Dispatcher.CheckAccess())
            {
                this.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Normal, (Action)delegate { SaveSettings(); });
                return;
            }
            else
            {
                ParsecClient.Properties.Settings.Default.CombatLogFolder = ((ParsecWindow)MainWindow).LogFolderPath;
                ParsecClient.Properties.Settings.Default.ShowFilters = ((ParsecWindow)MainWindow).pnlFilters.Visibility == Visibility.Visible;
                ParsecClient.Properties.Settings.Default.MainWindowHeight = ((ParsecWindow)MainWindow).Height;
                ParsecClient.Properties.Settings.Default.MainWindowWidth = ((ParsecWindow)MainWindow).Width;
                ParsecClient.Properties.Settings.Default.MainWindowTop = ((ParsecWindow)MainWindow).Top;
                ParsecClient.Properties.Settings.Default.MainWindowLeft = ((ParsecWindow)MainWindow).Left;
                ParsecClient.Properties.Settings.Default.LastUsedRaidKey = ((ParsecWindow)MainWindow).CurrentRaidGroup.Name;
                ParsecClient.Properties.Settings.Default.MainTopMost = ((ParsecWindow)MainWindow).Topmost;
                ParsecClient.Properties.Settings.Default.IsStreamMode = this.IsStreamMode;
                ParsecClient.Properties.Settings.Default.IsSoftwareRenderingMode = this.IsSoftwareRenderingMode;
                ParsecClient.Properties.Settings.Default.MainOpacity = ((ParsecWindow)MainWindow).Opacity;
                ParsecClient.Properties.Settings.Default.RaidGroups = this.RaidGroups.Serialize();
                ParsecClient.Properties.Settings.Default.RecentFiles = this.RecentFiles.Serialize();
                ParsecClient.Properties.Settings.Default.TimerVolume = VolumeSetting;

                ParsecClient.Properties.Settings.Default.DefaultTimeServer = TimeServerDefault;
                ParsecClient.Properties.Settings.Default.EnableTimeSync = TimeSyncEnabled;
                ParsecClient.Properties.Settings.Default.TimeServerHostName = TimeServerHostNameSetting;
                ParsecClient.Properties.Settings.Default.TimeServerPort = TimeServerPortSetting;

                if (((ParsecWindow)MainWindow).ddlRaidReportType.SelectedValue != null && ((ParsecWindow)MainWindow).ddlRaidReportType.SelectedValue is string)
                    ParsecClient.Properties.Settings.Default.RaidDetailsSortKey = (string)((ParsecWindow)MainWindow).ddlRaidReportType.SelectedValue;
                ParsecClient.Properties.Settings.Default.Save();
                TimerDefinitionCollection.SaveTimerDefinitions(TimerDefinitions);
            }
        }
        public void UpdateTimeSync(bool writeToLog)
        {
            if (TimeSyncEnabled && TimeServerOk)
            {
                string timeServerHostName = TimeServerDefault ? DefaultTimeServer : TimeServerHostNameSetting;
                int timeServerPort = TimeServerDefault ? 123 : TimeServerPortSetting;
                if (!string.IsNullOrEmpty(timeServerHostName))
                {
                    if (SNTPTimeServer == null || SNTPTimeServer.TimeServerHost != timeServerHostName || SNTPTimeServer.TimeServerPort != timeServerPort)
                        SNTPTimeServer = new SNTPClient(timeServerHostName, timeServerPort);
                    try
                    {
                        SNTPTimeServer.Connect();
                        LastTimeServerUpdate = DateTime.UtcNow;
                    }
                    catch (Exception ex)
                    {
                        //write to log
                        ((App)Application.Current).HandleError(null, "Time Server Connect Error", ex, null, true);
                    }
                    if (!SNTPTimeServer.IsResponseValid())
                        TimeServerOk = false;
                    if (writeToLog)
                        Logger.WriteInfo(string.Format("Time Server ({2}:{3}) Status: {0} Offset: {1}", SNTPTimeServer.IsResponseValid() ? "OK" : "OFFLINE", SNTPTimeServer.IsResponseValid() ? SNTPTimeServer.LocalClockOffset.ToString() : "0", timeServerHostName, timeServerPort.ToString()));
                }
            }
        }
        public void LoadSystemSettings()
        {
            IsStreamMode = ParsecClient.Properties.Settings.Default.IsStreamMode;
            IsSoftwareRenderingMode = ParsecClient.Properties.Settings.Default.IsSoftwareRenderingMode;
            VolumeSetting = ParsecClient.Properties.Settings.Default.TimerVolume;
            TimeServerDefault = ParsecClient.Properties.Settings.Default.DefaultTimeServer;
            TimeSyncEnabled = ParsecClient.Properties.Settings.Default.EnableTimeSync;
            TimeServerHostNameSetting = ParsecClient.Properties.Settings.Default.TimeServerHostName;
            TimeServerPortSetting = ParsecClient.Properties.Settings.Default.TimeServerPort;
            Audio.Volume = VolumeSetting;
        }
        public void LoadWindowSettings()
        {
            if (!this.Dispatcher.CheckAccess())
            {
                this.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Normal, (Action)delegate { LoadWindowSettings(); });
                return;
            }
            else
            {
                if (!string.IsNullOrEmpty(ParsecClient.Properties.Settings.Default.CombatLogFolder))
                    ((ParsecWindow)MainWindow).LogFolderPath = ParsecClient.Properties.Settings.Default.CombatLogFolder;
                else
                    ((ParsecWindow)MainWindow).LogFolderPath = System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), DefaultLogPath);
                
                ((ParsecWindow)MainWindow).Height = ParsecClient.Properties.Settings.Default.MainWindowHeight;
                ((ParsecWindow)MainWindow).Width = ParsecClient.Properties.Settings.Default.MainWindowWidth;
                if (ParsecClient.Properties.Settings.Default.MainWindowTop >= SystemParameters.VirtualScreenTop 
                    && ParsecClient.Properties.Settings.Default.MainWindowLeft >= SystemParameters.VirtualScreenLeft)
                {
                    ((ParsecWindow)MainWindow).Top = ParsecClient.Properties.Settings.Default.MainWindowTop;
                    ((ParsecWindow)MainWindow).Left = ParsecClient.Properties.Settings.Default.MainWindowLeft;
                }
                else
                {
                    ((ParsecWindow)MainWindow).Top = SystemParameters.VirtualScreenTop;
                    ((ParsecWindow)MainWindow).Left = SystemParameters.VirtualScreenLeft;
                }
                if (ParsecClient.Properties.Settings.Default.ShowFilters)
                {
                    ((ParsecWindow)MainWindow).pnlFilters.Visibility = System.Windows.Visibility.Visible;
                    ((ParsecWindow)MainWindow).btnFilterExpand.Visibility = System.Windows.Visibility.Collapsed;
                    ((ParsecWindow)MainWindow).btnFilterCollapse.Visibility = System.Windows.Visibility.Visible;
                }
                else
                {
                    ((ParsecWindow)MainWindow).pnlFilters.Visibility = System.Windows.Visibility.Collapsed;
                    ((ParsecWindow)MainWindow).btnFilterExpand.Visibility = System.Windows.Visibility.Visible;
                    ((ParsecWindow)MainWindow).btnFilterCollapse.Visibility = System.Windows.Visibility.Collapsed;
                }
                ((ParsecWindow)MainWindow).SetRaidReportTypeDropDownValue(ParsecClient.Properties.Settings.Default.RaidDetailsSortKey);
                ((ParsecWindow)MainWindow).Topmost = ParsecClient.Properties.Settings.Default.MainTopMost;
                if (ParsecClient.Properties.Settings.Default.MainOpacity < .1)
                    ParsecClient.Properties.Settings.Default.MainOpacity = .1;
                ((ParsecWindow)MainWindow).Opacity = ParsecClient.Properties.Settings.Default.MainOpacity;
                bool saveNeeded = false;
                if (!string.IsNullOrEmpty(ParsecClient.Properties.Settings.Default.RaidGroups))
                {
                    try
                    {
                        RaidGroups = ParsecClient.Properties.Settings.Default.RaidGroups.Deserialize<List<RaidGroup>>(false);
                    }
                    catch
                    {
                        //fix raid groups
                        ParsecClient.Properties.Settings.Default.RaidGroups = this.RaidGroups.Serialize();
                        saveNeeded = true;
                    }
                }
                else
                {
                    RaidGroups = new List<RaidGroup>();
                }
                ((ParsecWindow)MainWindow).CurrentRaidGroup = new RaidGroup();
                if (!string.IsNullOrEmpty(ParsecClient.Properties.Settings.Default.LastUsedRaidKey))
                {
                    RaidGroup c = RaidGroups.FirstOrDefault(x => string.Compare(x.Name, ParsecClient.Properties.Settings.Default.LastUsedRaidKey, true) == 0);
                    if (c != null)
                    {
                        ((ParsecWindow)MainWindow).CurrentRaidGroup = c;
                    }
                    else
                    {
                        ParsecClient.Properties.Settings.Default.LastUsedRaidKey = null;
                        saveNeeded = true;
                    }
                }
                if (!string.IsNullOrEmpty(ParsecClient.Properties.Settings.Default.RecentFiles))
                {
                    try
                    {
                        RecentFiles = ParsecClient.Properties.Settings.Default.RecentFiles.Deserialize<List<string>>(false);
                    }
                    catch
                    {
                        //fix raid groups
                        ParsecClient.Properties.Settings.Default.RecentFiles = this.RecentFiles.Serialize();
                        saveNeeded = true;
                    }
                }
                if (saveNeeded)
                    ParsecClient.Properties.Settings.Default.Save();
                lock (TimerDefinitionLock)
                {
                    TimerDefinitions = TimerDefinitionCollection.RetrieveTimerDefinitions();
                    TimerDefinitions.ForEach(x => x.IsEnabled = false);
                    if (TimerDefinitions.Count == 0)
                    {
                        TimerDefinitions = TimerDefinition.GetDefaults();
                        TimerDefinitionCollection.SaveTimerDefinitions(TimerDefinitions);
                    }
                }
            }
        }
        public void ApplyCharacterSettings(string characterName)
        {
            if (!this.Dispatcher.CheckAccess())
            {
                this.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Normal, (Action)delegate { ApplyCharacterSettings(characterName); });
                return;
            }
            else
            {
                CharacterSettings settings = AllCharacterSettings.FirstOrDefault(x => x.CharacterName == characterName) ?? new CharacterSettings();
                StatPopOut.Width = settings.StatPopOutWidth;
                StatPopOut.Top = settings.StatPopOutTop;
                StatPopOut.Left = settings.StatPopOutLeft;
                StatPopOut.SetBackgroundOpacity(settings.StatPopOutOpacity);
                RaidDpsPopOut.Width = settings.RaidDpsPopOutWidth;
                RaidDpsPopOut.Top = settings.RaidDpsPopOutTop;
                RaidDpsPopOut.Left = settings.RaidDpsPopOutLeft;
                RaidDpsPopOut.SetBackgroundOpacity(settings.RaidDpsPopOutOpacity);
                RaidHpsPopOut.Width = settings.RaidHpsPopOutWidth;
                RaidHpsPopOut.Top = settings.RaidHpsPopOutTop;
                RaidHpsPopOut.Left = settings.RaidHpsPopOutLeft;
                RaidHpsPopOut.SetBackgroundOpacity(settings.RaidHpsPopOutOpacity);
                RaidTpsPopOut.Width = settings.RaidTpsPopOutWidth;
                RaidTpsPopOut.Top = settings.RaidTpsPopOutTop;
                RaidTpsPopOut.Left = settings.RaidTpsPopOutLeft;
                RaidTpsPopOut.SetBackgroundOpacity(settings.RaidTpsPopOutOpacity);
                RaidTpsPopOut.TankMode = settings.RaidTpsTankMode;
                StatStopWatchPopOut.Width = settings.PvpStatsPopOutWidth;
                StatStopWatchPopOut.Top = settings.PvpStatsPopOutTop;
                StatStopWatchPopOut.Left = settings.PvpStatsPopOutLeft;
                StatStopWatchPopOut.SetBackgroundOpacity(settings.PvpStatsPopOutOpacity);
                TimerPopOut.Width = settings.TimerPopOutWidth;
                TimerPopOut.Top = settings.TimerPopOutTop;
                TimerPopOut.Left = settings.TimerPopOutLeft;
                TimerPopOut.SetBackgroundOpacity(settings.TimerPopOutOpacity);
                DpsMeterPopOut.Width = settings.DpsMeterPopOutWidth;
                DpsMeterPopOut.Top = settings.DpsMeterPopOutTop;
                DpsMeterPopOut.Left = settings.DpsMeterPopOutLeft;
                DpsMeterPopOut.SetBackgroundOpacity(settings.DpsMeterPopOutOpacity);
                DpsMeterPopOut.CurrentMode = (DpsMeter.DamageViewMode)settings.DpsMeterViewMode;
                var timerDefs = GetTimerDefinitions();
                foreach (var td in timerDefs)
                {
                    td.IsEnabled = settings.EnabledTimers.Contains(td.Description);
                }
                ((ParsecWindow)MainWindow).BindTimerDefinitions();
                ((ParsecWindow)MainWindow).ApplyCharacterSettings(settings);
            }
        }
        public void SaveCharacterSettings(string characterName)
        {
            if (!this.Dispatcher.CheckAccess())
            {
                this.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Normal, (Action)delegate { SaveCharacterSettings(characterName); });
                return;
            }
            else
            {
                //create charactersettings object with settings
                if (!string.IsNullOrEmpty(characterName))
                {
                    CharacterSettings settings = new CharacterSettings()
                    {
                        CharacterName = characterName,
                        StatPopOutWidth = StatPopOut.Width,
                        StatPopOutTop = StatPopOut.Top,
                        StatPopOutLeft = StatPopOut.Left,
                        StatPopOutOpacity = StatPopOut.GetBackgroundOpacity(),
                        RaidDpsPopOutWidth = RaidDpsPopOut.Width,
                        RaidDpsPopOutTop = RaidDpsPopOut.Top,
                        RaidDpsPopOutLeft = RaidDpsPopOut.Left,
                        RaidDpsPopOutOpacity = RaidDpsPopOut.GetBackgroundOpacity(),
                        RaidHpsPopOutWidth = RaidHpsPopOut.Width,
                        RaidHpsPopOutTop = RaidHpsPopOut.Top,
                        RaidHpsPopOutLeft = RaidHpsPopOut.Left,
                        RaidHpsPopOutOpacity = RaidHpsPopOut.GetBackgroundOpacity(),
                        RaidTpsPopOutWidth = RaidTpsPopOut.Width,
                        RaidTpsPopOutTop = RaidTpsPopOut.Top,
                        RaidTpsPopOutLeft = RaidTpsPopOut.Left,
                        RaidTpsPopOutOpacity = RaidTpsPopOut.GetBackgroundOpacity(),
                        PvpStatsPopOutWidth = StatStopWatchPopOut.Width,
                        PvpStatsPopOutTop = StatStopWatchPopOut.Top,
                        PvpStatsPopOutLeft = StatStopWatchPopOut.Left,
                        PvpStatsPopOutOpacity = StatStopWatchPopOut.GetBackgroundOpacity(),
                        TimerPopOutWidth = TimerPopOut.Width,
                        TimerPopOutTop = TimerPopOut.Top,
                        TimerPopOutLeft = TimerPopOut.Left,
                        TimerPopOutOpacity = TimerPopOut.GetBackgroundOpacity(),
                        DpsMeterPopOutWidth = DpsMeterPopOut.Width,
                        DpsMeterPopOutTop = DpsMeterPopOut.Top,
                        DpsMeterPopOutLeft = DpsMeterPopOut.Left,
                        DpsMeterPopOutOpacity =DpsMeterPopOut.GetBackgroundOpacity(),
                        ShowStatPopOut = ((ParsecWindow)MainWindow).btnStats.IsChecked,
                        ShowRaidDpsPopOut = ((ParsecWindow)MainWindow).btnRaidDps.IsChecked,
                        ShowRaidTpsPopOut = ((ParsecWindow)MainWindow).btnRaidTps.IsChecked,
                        ShowPvpStatsPopOut = ((ParsecWindow)MainWindow).btnStatStopWatch.IsChecked,
                        ShowRaidHpsPopOut = ((ParsecWindow)MainWindow).btnRaidHps.IsChecked,
                        ShowTimerPopOut = ((ParsecWindow)MainWindow).btnTimerPop.IsChecked,
                        ShowDpsMeterPopOut = ((ParsecWindow)MainWindow).btnDpsMeter.IsChecked,
                        EnabledTimers = TimerDefinitions.Where(x => x.IsEnabled).Select(x => x.Description).ToList(),
                        DpsMeterViewMode = (int)DpsMeterPopOut.CurrentMode,
                        RaidTpsTankMode = RaidTpsPopOut.TankMode,
                        AbsorbShieldValue = ((ParsecWindow)MainWindow).AbsorbShieldValue,
                        UseBasicDpsView = ((ParsecWindow)MainWindow).rdoDamageOutCollapsed.IsChecked ?? false
                    };
                    if (((ParsecWindow)MainWindow).ddlRaidReportType.SelectedValue != null && ((ParsecWindow)MainWindow).ddlRaidReportType.SelectedValue is string)
                        settings.RaidDetailsSortKey = (string)((ParsecWindow)MainWindow).ddlRaidReportType.SelectedValue;
                    AllCharacterSettings = CharacterSettingsCollection.SaveCharacterSettings(settings);
                }
            }
        }
        public void AddRecentFile(string filePath)
        {
            RecentFiles.Remove(filePath);
            int skipcount = 0;
            if (RecentFiles.Count > 4)
                skipcount = RecentFiles.Count - 4;
            RecentFiles = RecentFiles.Skip(skipcount).Take(4).ToList();
            RecentFiles.Add(filePath);
        }
        public void ShuttingDown()
        {
            if (StatPopOut != null)
                StatPopOut.Close();
            if (StatStopWatchPopOut != null)
                StatStopWatchPopOut.Close();
            if (RaidDpsPopOut != null)
                RaidDpsPopOut.Close();
            if (RaidHpsPopOut != null)
                RaidHpsPopOut.Close();
            if (RaidTpsPopOut != null)
                RaidTpsPopOut.Close();
            if (TimerPopOut != null)
                TimerPopOut.Close();
            if (DpsMeterPopOut != null)
                DpsMeterPopOut.Close();
            if (MyMessageWindow != null)
                MyMessageWindow.Close();
            if (StatPopOut != null)
            {
                StatPopOut = null;
            }
            if (StatStopWatchPopOut != null)
            {
                StatStopWatchPopOut = null;
            }
            if (RaidDpsPopOut != null)
            {
                RaidDpsPopOut = null;
            }
            if (RaidHpsPopOut != null)
            {
                RaidHpsPopOut = null;
            }
            if (RaidTpsPopOut != null)
            {
                RaidTpsPopOut = null;
            }
            if (PopUpHost != null)
            {
                PopUpHost = null;
            }
            MyMessageWindow = null;
            RecentFiles = null;
            RaidGroups = null;
        }
        public static string GetServicePayload(string payload)
        {
            Random rnd = new Random();
            int i = rnd.Next(0, 1000);
            string prefix = i.ToString().PadLeft(3, '0');
            string token = prefix + payload;
            return ParsecParser.Communication.AESThenHMAC.SimpleEncryptWithPassword(token, EncryptionKey);
        }
        //static System.Threading.Mutex OurMutex = new System.Threading.Mutex(true, "PARSEC SWTOR Combat Log Parser");
        ///// <summary>
        ///// The main entry point for the application.
        ///// </summary>
        //[STAThread]
        //public static void Main()
        //{
        //    try
        //    {
        //        if (OurMutex.WaitOne(TimeSpan.Zero, true))
        //        {
        //            var application = new App();
        //            application.InitializeComponent();1
        //            application.Run();
        //            OurMutex.ReleaseMutex();
        //        }
        //        else
        //        {
        //            MessageBox.Show("You attempted to launch Parsec twice. This is not allowed.", "Parsec Error");
        //        }
        //    }
        //    catch(Exception ex)
        //    {
        //        MessageBox.Show("The Emperor has made a critical error and the time for our attack has come! " + ex.Message, "Parsec Error");
        //    }
        //}
    }
}
